//
//  Share.swift
//  Share
//
//  Created by MBA on 2020/10/4.
//  Copyright © 2020 MBA. All rights reserved.
//

import Foundation
import SQLite
import Alamofire
import Combine




struct  Share: Codable , Identifiable {
    
    var id = 0
    var name:String=""
    var code:String=""
    var price:String=""
    var yestodayprice:String=""
    var ratioIn:String=""
    var ratioOut:String=""
    
    
    var stores: [Store] = [Store]()
    var outstores: [Store] = [Store]()
    
}


extension Share{
    
    /**
     获取委买
     */
    func fitteInstores() ->[PreTransactionModen]{
        var instores: [PreTransactionModen] = []
        
        let store =  getminPriceStore()
        if store != nil {
            
            let inprice = store!.price * (Float(ratioIn) ?? 0.95)
            let minprice = ((Float(yestodayprice) ?? 0.00)*0.90)
            let maxprice = ((Float(yestodayprice) ?? 0.00)*1.10)
            if (inprice >= minprice &&  inprice <= maxprice)  {
                instores.append(PreTransactionModen.init(share: self, store: store!))
            }
        }
        
        return instores
    }
    
    /**
     获取委卖
     */
    func fitteOutstores() ->[PreTransactionModen] {
        var outstores: [PreTransactionModen] = []
        
        let store =  getminPriceStore()
        if store != nil {
            let outprice = store!.price * (Float(ratioOut) ?? 1.10)
            let minprice = ((Float(yestodayprice) ?? 0.00)*0.90)
            let maxprice = ((Float(yestodayprice) ?? 0.00)*1.10)
            if (outprice >= minprice && outprice <= maxprice)  {
                outstores.append(PreTransactionModen.init(share: self, store: store!))
            }
        }
        
        return outstores
    }
    
    func getAllNum() -> Int {
        if self.stores.count == 0 {
            return 0
        }
        var num = 0
        for item in self.stores {
            if item.num>0 {
                num = num+item.num
            }
        }
        return num
    }
    
    func getAllPrice() -> Float {
        
        if self.stores.count == 0 {
            return Float(0)
        }
        var inprice:Float = 0
        for item in self.stores {
            inprice = inprice+(item.price*Float(item.num))
        }
        return inprice
    }
    
    func getInPrice()  -> Float{
        if self.stores.count == 0 {
            return Float(0)
        }
        var inprice:Float = self.stores[0].price
        for item in self.stores {
            if item.num>0 {
                inprice = min(item.price, inprice)
            }
        }
        return inprice*(Float(ratioIn) ?? 0.95)
    }
    
    func getOutPrice() -> Float {
        if self.stores.count == 0 {
            return Float(0)
        }
        var inprice:Float = self.stores[0].price
        for item in self.stores {
            if item.num>0 {
                inprice = min(item.price, inprice)
            }
        }
        return inprice*(Float(ratioOut) ?? 1.05)
    }
    
    func getminPriceStore()  -> Store?{
        if self.stores.count == 0 {
            return nil
        }
        var store = self.stores[0]
        var inprice:Float = self.stores[0].price
        for item in self.stores {
            if item.num>0 {
                if item.price < inprice {
                    inprice = item.price
                    store = item;
                }
            }
        }
        return store
    }
    
    /**
     获取收益
     */
    func getIncome() -> Float {
        var income:Float = 0
        for store in outstores {
            if store.state == 1 {
                let outprice:Float = store.outprice ?? 0.00
                let price:Float = store.price
                let fee:Float = store.fee ?? 0.00
                income = income + ((outprice - price) * Float(store.num))-fee
            }
        }
        return income
    }
    
    
}
/**
 sinajs
 */
extension Share{
    /**
     获取当前价格
     */
   func updatePrice(finesh:@escaping  (Error?) ->  ())  {
        
        if id>0 {
            sinaPrice { (error, datas) in
                if error != nil{
                    finesh(error)
                }else{
                    if datas?.count ?? 0>3 {
                        var tshare = Share()
                        if( (Float((datas![3])) ?? 0) > 0){
                            tshare.id = self.id
                            tshare.price = "\(datas![3])"
                            tshare.yestodayprice =  "\(datas![2])"
                            tshare.db_share(id: tshare.id) { (error, share) in
                                finesh(error)
                            }
                        }else{
                            finesh(error)
                        }
                    }else{
                        finesh(NSError.init(domain: "获取股票价格错误", code: -1, userInfo: nil))
                    }
                }
            }

        }else{
            finesh(NSError.init(domain: "id is nil", code: -1, userInfo: nil))
        }
    }
    //    0：”大秦铁路”，股票名字；
    //    1：”27.55″，今日开盘价；
    //    2：”27.25″，昨日收盘价；
    //    3：”26.91″，当前价格；
    //    4：”27.55″，今日最高价；
    //    5：”26.20″，今日最低价；
    //    6：”26.91″，竞买价，即“买一”报价；
    //    7：”26.92″，竞卖价，即“卖一”报价；
    //    8：”22114263″，成交的股票数，由于股票交易以一百股为基本单位，所以在使用时，通常把该值除以一百；
    //    9：”589824680″，成交金额，单位为“元”，为了一目了然，通常以“万元”为成交金额的单位，所以通常把该值除以一万；
    //    10：”4695″，“买一”申请4695股，即47手；
    //    11：”26.91″，“买一”报价；
    //    12：”57590″，“买二”
    //    13：”26.90″，“买二”
    //    14：”14700″，“买三”
    //    15：”26.89″，“买三”
    //    16：”14300″，“买四”
    //    17：”26.88″，“买四”
    //    18：”15100″，“买五”
    //    19：”26.87″，“买五”
    //    20：”3100″，“卖一”申报3100股，即31手；
    //    21：”26.92″，“卖一”报价
    //    (22, 23), (24, 25), (26,27), (28, 29)分别为“卖二”至“卖四的情况”
    //    30：”2008-01-11″，日期；
    //    31：”15:05:32″，时间；
}

// MARK: DB
extension Share{
    
    static func row_to(row:SQLite.Row)->Share{
        var share = Share()
        share.id = Int(row[Expression<Int64>("id")])
        share.name = "\(row[Expression<String?>("name")] ?? "")"
        share.code = "\(row[Expression<String?>("code")] ?? "")"
        share.price = "\(row[Expression<String?>("price")] ?? "")"
        share.yestodayprice = "\(row[Expression<String?>("yestodayprice")] ?? "")"
        share.ratioIn = "\(row[Expression<String?>("ratioIn")] ?? "")"
        share.ratioOut = "\(row[Expression<String?>("ratioOut")] ?? "")"
        share.stores = Store.db_stores(shareid: Int64(share.id)).filter({ (store) -> Bool in
            Int(store.state ?? 0) == 0
        })
        share.outstores = Store.db_stores(shareid: Int64(share.id)).filter({ (store) -> Bool in
            store.state == 1
        })
        return share
    }
    
    static func db_shares(finesh:@escaping  (NSError?, [Share]?) ->  ()) {
        
        let share = Table("Share")
        do {
            let query = try db?.prepare(share)
            let list:[Share] =  query?.map({ row -> Share in
                return Share.row_to(row: row)
            }) ?? [Share]()
            finesh(nil,list)
        } catch {
            debugPrint("\(self) \(#function) error db_shares: \(error)")
            finesh(error as NSError,nil)
        }
    }
    
    static func db_share(id:Int, finesh:@escaping  (NSError?, Share?) ->  ()) {
        
        let share = Table("Share")
        do {
            let query = try db?.prepare(share.filter(Expression<Int64>("id") == Int64(id)))
            let list:[Share] =  query?.map({ row -> Share in
                return Share.row_to(row: row)
            }) ?? [Share]()
            if list.count>0 {
                finesh(nil,list[0])
            }else{
                finesh(NSError.init(domain: "share not found" , code: -1, userInfo: nil),nil)
            }
            
        } catch {
            debugPrint("\(self) \(#function) error db_shares_id: \(error)")
            finesh(error as NSError,nil)
        }
    }
    
    func db_share(id:Int?,finesh:@escaping  (Error?, Share?) ->  ()) {
        let share = Table("Share")
        do {
            if nil != id {
                let alice = share.filter(Expression<Int64>("id") == Int64(id!))
                var setters = [SQLite.Setter]()
                if name.count>0 {
                    setters.append(Expression<String?>("name") <- name)
                }
                if code.count>0 {
                    setters.append(Expression<String?>("code") <- code)
                }
                if price.count>0 {
                    setters.append(Expression<String?>("price") <- price)
                }
                if yestodayprice.count>0 {
                    setters.append(Expression<String?>("yestodayprice") <- yestodayprice)
                }
                if ratioIn.count>0 {
                    setters.append(Expression<String?>("ratioIn") <- ratioIn)
                }
                
                if ratioOut.count>0 {
                    setters.append(Expression<String?>("ratioOut") <- ratioOut)
                }
                
                let rowid =  try db?.run(alice.update(setters))
                if rowid ?? 0>0{
                    finesh(nil,self)
                }else{
                    finesh(NSError.init(domain: "share not found" , code: -1, userInfo: nil),nil)
                }
                
            }else{
                let rowid = try db?.run(share.insert(
                    Expression<String?>("name") <- name,
                    Expression<String?>("code") <- code,
                    Expression<String?>("price") <- price,
                    Expression<String?>("yestodayprice") <- yestodayprice,
                    Expression<String?>("ratioIn") <- ratioIn,
                    Expression<String?>("ratioOut") <- ratioOut
                ))
                if rowid ?? 0>0{
                    var temshare = self
                    temshare.id = Int(rowid!)
                    finesh(nil,temshare)
                }else{
                    finesh(NSError.init(domain: "share not found" , code: -1, userInfo: nil),nil)
                }
                
            }
        } catch {
            debugPrint("\(self) \(#function) error: \(error)")
            finesh(error as NSError,nil)
        }
        
    }
    
 
    
    func db_delete(finesh:@escaping  (NSError?) ->  ())  {
        let share = Table("Share")
        do {
            let alice = share.filter(Expression<Int64>("id") == Int64(id))
            let rowid = try db?.run(alice.delete())
            if rowid ?? 0>0{
                var temshare = self
                temshare.id = Int(rowid!)
                finesh(nil)
            }else{
                finesh(NSError.init(domain: "share not found" , code: -1, userInfo: nil))
            }
            
        } catch {
            debugPrint("\(self) \(#function) error: \(error)")
            finesh(error as NSError)
        }
    }
    
    
}

// MARK: HTTP
extension Share{
    
    static func api_shares(finesh:@escaping  (NSError?, [Share]?) ->  ()){
        
        let url = "\(baseurl)/shares"
        let parameters = ["_start":0,"_limit":10]
        AF.request(url, method: .get, parameters: parameters){ urlRequest in
            urlRequest.timeoutInterval = 5
        }.responseJSON { (response) in
            
            switch response.result {
            case .success(let value):
                do{
                    let jsonData = try JSONSerialization.data(withJSONObject: value as Any, options: [])
                    let shares = try JSONDecoder().decode([Share].self, from: jsonData)
                    finesh(nil, shares)
                }
                catch {
                    finesh(error as NSError, nil)
                }
                
                
            case .failure(let error):
                print("error")
                finesh(NSError.init(domain: error.localizedDescription , code: -1, userInfo: nil),nil)
                
            }
        }
    }
    
    static func api_share(id:Int, finesh:@escaping  (NSError?, Share?) ->  ()){
        
        let url = "\(baseurl)/shares/\(id)"
        AF.request(url, method: .get){ urlRequest in
            urlRequest.timeoutInterval = 5
        }.responseJSON { (response) in
            
            switch response.result {
            case .success(let value):
                do{
                    let jsonData = try JSONSerialization.data(withJSONObject: value as Any, options: [])
                    let share = try JSONDecoder().decode(Share.self, from: jsonData)
                    finesh(nil, share)
                }
                catch {
                    finesh(error as NSError, nil)
                }
                
                
            case .failure(let error):
                print("error")
                finesh(NSError.init(domain: error.localizedDescription , code: -1, userInfo: nil),nil)
                
            }
        }
    }
    
    /**新增/修改*/
    func api_share(id:Int?, finesh:@escaping  (NSError?, Share?) ->  ()){
        
        var url = "\(baseurl)/shares"
        if (id != 0) {
            url.append("/\(id!)")
        }
        
        let paramedata = try? JSONEncoder().encode(self)
        let parameters = try? JSONSerialization.jsonObject(with: paramedata!, options: .mutableContainers)
        
        var stores = [Int]()
        for item in self.stores {
            stores.append(item.id)
        }
        var parame = parameters as? Parameters
        parame?["stores"] = stores
        
        AF.request(url, method:  (id != 0) ? .put : .post, parameters: parame){ urlRequest in
            urlRequest.timeoutInterval = 5
            
        }.responseJSON { (response) in
            
            switch response.result {
            case .success(let value):
                do{
                    
                    let jsonData = try JSONSerialization.data(withJSONObject: value as Any, options: [])
                    let share = try JSONDecoder().decode(Share.self, from: jsonData)
                    finesh(nil, share)
                }
                catch {
                    finesh(error as NSError, nil)
                }
            case .failure(let error):
                print("\(error)")
                finesh(NSError.init(domain: error.localizedDescription , code: -1, userInfo: nil),nil)
                
            }
            
        }
    }
    
    func api_delete(finesh:@escaping  (NSError?) ->  ()) {
        let url = "\(baseurl)/shares/\(id)"
        AF.request(url, method: .delete){ urlRequest in
            urlRequest.timeoutInterval = 5
        }.responseJSON { (response) in
            
            switch response.result {
            case .success(let _):
                
                finesh(nil)
                
            case .failure(let error):
                print("error")
                finesh(NSError.init(domain: error.localizedDescription , code: -1, userInfo: nil))
                
            }
        }
    }
    
    func sinaPrice(finesh:@escaping  (Error?, [Substring]?) ->  ())  {
        
        if id>0 {
            AF.request("http://hq.sinajs.cn/list=\(code.lowercased())", method: .get)
                .responseString { (response) in
                    switch response.result {
                    case .success(let data):
        
                        let datas  = data.split(separator: ",")
                        finesh(nil,datas)

                    case .failure(let error):
                        finesh(error,nil)
                    }
                }
        }
    }
    //    0：”大秦铁路”，股票名字；
    //    1：”27.55″，今日开盘价；
    //    2：”27.25″，昨日收盘价；
    //    3：”26.91″，当前价格；
    //    4：”27.55″，今日最高价；
    //    5：”26.20″，今日最低价；
    //    6：”26.91″，竞买价，即“买一”报价；
    //    7：”26.92″，竞卖价，即“卖一”报价；
    //    8：”22114263″，成交的股票数，由于股票交易以一百股为基本单位，所以在使用时，通常把该值除以一百；
    //    9：”589824680″，成交金额，单位为“元”，为了一目了然，通常以“万元”为成交金额的单位，所以通常把该值除以一万；
    //    10：”4695″，“买一”申请4695股，即47手；
    //    11：”26.91″，“买一”报价；
    //    12：”57590″，“买二”
    //    13：”26.90″，“买二”
    //    14：”14700″，“买三”
    //    15：”26.89″，“买三”
    //    16：”14300″，“买四”
    //    17：”26.88″，“买四”
    //    18：”15100″，“买五”
    //    19：”26.87″，“买五”
    //    20：”3100″，“卖一”申报3100股，即31手；
    //    21：”26.92″，“卖一”报价
    //    (22, 23), (24, 25), (26,27), (28, 29)分别为“卖二”至“卖四的情况”
    //    30：”2008-01-11″，日期；
    //    31：”15:05:32″，时间；
}

// MARK: TESTDATA
extension Share{
    
    static let _shares:[Share] = [
        Share.init(id:0, name: "积分科技", code: "300022",price: "12.00", stores:Store._stores),
        Share.init(id:1, name: "科技ETF", code: "300022",price: "12.00", stores:Store._stores)
    ]
}

